package com.guiwu.gteway.industryapp.Frame;

import com.google.gson.JsonObject;
import com.guiwu.gteway.industryapp.util.HexUtil;
import com.guiwu.gteway.industryapp.util.MyLog;

import java.io.IOException;

/**
 * Created by qiaoguan on 2018/3/27. 组帧类
 */

public class FrameHelper {

    //写线圈  功能码05 RTU
    public static String writeCoilRTU(int slaveAdr, int addr, boolean state){
        StringBuilder sb = new StringBuilder();
        String slAd = String.format("%02x",slaveAdr).toUpperCase();
        sb.append(slAd).append("05");
        String regAd = String.format("%04x",addr).toUpperCase();
        String value = state ? "FF00" : "0000";
        sb.append(regAd).append(value);
        String codeCrc = sb.toString();
        sb.append(CRCModbus(codeCrc));
        return sb.toString().toUpperCase();
    }

    //写寄存器 功能码06 RTU
    public static String wrightRegisterRTU(int slaveAdr , int addr , int valueInt){
        StringBuilder sb = new StringBuilder();
        String slAd = String.format("%02x",slaveAdr).toUpperCase();
        sb.append(slAd).append("06");
        String regAd = String.format("%04x",addr).toUpperCase();
        String value = String.format("%04x",valueInt);
        sb.append(regAd).append(value);
        String codeCrc = sb.toString();
        sb.append(CRCModbus(codeCrc));
        return sb.toString().toUpperCase();
    }

    //写线圈  功能码05 ASCII
    public static String writeCoilASSIC(int slaveAdr,int addr,boolean state){
        StringBuilder sb = new StringBuilder();
        String slAd = String.format("%02x",slaveAdr).toUpperCase();
        sb.append(slAd).append("05");
        String regAd = String.format("%04x",addr).toUpperCase();
        String value = state ? "FF00" : "0000";
        sb.append(regAd).append(value);
        String code = sb.toString();
        String LRC = getLRC(HexUtil.hexStringToBytes(code));
        sb.insert(0,':');
        sb.append(LRC);
        sb.append("\r\n");
        return sb.toString();
    }

    //写寄存器  功能码06 ASCII
    public static String writeRegistASSIC(int slaveAdr,int addr,int valueInt){
        StringBuilder sb = new StringBuilder();
        String slAd = String.format("%02x",slaveAdr).toUpperCase();
        sb.append(slAd).append("06");
        String regAd = String.format("%04x",addr).toUpperCase();
        String value = String.format("%04x",valueInt).toUpperCase();
        sb.append(regAd).append(value);
        String code = sb.toString();
        String LRC = getLRC(HexUtil.hexStringToBytes(code));
        sb.insert(0,':');
        sb.append(LRC);
        sb.append("\r\n");
        return sb.toString();
    }

    //设备控制，返回json
    public static String cmdForContorl(String streamId,String cmd, String protocal) throws IOException{
            JsonObject object = new JsonObject();
            object.addProperty("streamId",streamId);
            object.addProperty("operation","write");
            object.addProperty("cmmdContent",cmd);
            object.addProperty("protocol",protocal);
            return object.toString();
    }


    //高低换位
    private static String CRCModbus(String data){
        StringBuilder CRC16 = new StringBuilder(getCrc16(HexUtil.hexStringToBytes(data)));
        //High to Low
        String CRCHigh = CRC16.substring(0,2);
        String CRCLow = CRC16.substring(2,4);
        CRC16.replace(0,4,CRCLow + CRCHigh);
        return CRC16.toString();
    }

    //CRC16
    private static String getCrc16(byte[] arr_buff) {
        int len = arr_buff.length;

        //预置 1 个 16 位的寄存器为十六进制FFFF, 称此寄存器为 CRC寄存器。
        int crc = 0xFFFF;
        int i, j;
        for (i = 0; i < len; i++) {
            //把第一个 8 位二进制数据 与 16 位的 CRC寄存器的低 8 位相异或, 把结果放于 CRC寄存器
            crc = ((crc & 0xFF00) | (crc & 0x00FF) ^ (arr_buff[i] & 0xFF));
            for (j = 0; j < 8; j++) {
                //把 CRC 寄存器的内容右移一位( 朝低位)用 0 填补最高位, 并检查右移后的移出位
                if ((crc & 0x0001) > 0) {
                    //如果移出位为 1, CRC寄存器与多项式A001进行异或
                    crc = crc >> 1;
                    crc = crc ^ 0xA001;
                } else
                    //如果移出位为 0,再次右移一位
                    crc = crc >> 1;
            }
        }
        return String.format("%04x",crc);
    }

    //LRC
    public static String getLRC(byte[] data){
        int result = 0;
        for (int i = 0;i< data.length ;i++){
            result += (data[i] & 0xff);
        }
        result = ~result;
        result = (result & (0xff));
        result++;
        return Integer.toHexString(result).toUpperCase();
    }
}
